use nom::IResult;
use nom::bytes::complete::take_while;
use nom::bytes::streaming::tag;
use nom::branch::alt;
use nom::combinator::opt;
use nom::sequence::terminated;

use super::parse::Parse;
use super::word::words;

#[derive(Debug)]
pub struct StrValue<'a> {
    quotion:bool,
    inner:&'a str,
}

impl<'a> StrValue<'a> {
    pub fn quotion(&self) -> bool { self.quotion }
    pub fn inner(&self) -> &'a str { self.inner }
}

impl<'a> Parse<'a> for StrValue<'a> {
    fn parse(raw_str:&'a str) -> IResult<&'a str,Self> {
        let raw_str = raw_str.trim_start();
        let (raw_str,quotion) = opt(tag("\""))(raw_str)?;
        let (quotion,(raw_str,inner)) = if let Some(_) = quotion {
            (true,terminated(take_while(|c:char|c!='\"'), tag("\""))(raw_str)?)
        } else {
            (false,take_while(|c:char|!c.is_whitespace())(raw_str)?)
        };
        Ok((raw_str,Self{
            quotion:quotion,
            inner:inner,
        }))
    }
}

#[derive(Debug)]
pub struct VarStatement<'a> {
    var:&'a str,
    value:&'a str,
}

impl<'a> Parse<'a> for VarStatement<'a> {
    fn parse(raw_str:&'a str) -> IResult<&'a str,Self> {
        let raw_str = raw_str.trim_start();
        let (raw_str,var) = alt((
            words("chunking_algorithm"),
            words("chunking_method"),
            words("super_feature_algorithm"),
            words("super_feature_method"),
            words("working_directory"),
            words("log_level"),
            words("sf_num"),
            words("chunk_max_size"),
            words("chunk_min_size"),
            words("chunk_avg_size"),
            words("super_feature_subregion_num"),
            words("features_per_sf"),
            words("enable_sort_features"),
            words("find_in_recent_buffer"),
            words("find_in_write_buf"),
            words("find_in_read_cache"),
            words("find_in_index_store"),
        ))(raw_str)?;
        
        let raw_str = raw_str.trim_start();
        let (raw_str,_) = opt(tag("="))(raw_str)?;

        let (raw_str,value) = StrValue::parse(raw_str).expect(format!("{} has no value",var).as_str());
        Ok((raw_str,Self{
            var:var,
            value:value.inner(),
        }))
    }
}

impl<'a> VarStatement<'a> {
    pub fn var(&self) -> &str {
        self.var
    }

    pub fn value(&self) -> &str {
        self.value
    }
}

